<template>
  <div>
    <!-- <div>
      <button @click="insertText">insert text</button>
      <button @click="printHtml">print html</button>
      <button @click="disable">disable</button>
    </div> -->
    <div style="border: 1px solid #ccc; margin-top: 10px">
      <Toolbar
        :editor="editorRef"
        :defaultConfig="toolbarConfig"
        :mode="mode"
        style="border-bottom: 1px solid #ccc"
      />
      <Editor
        :defaultConfig="editorConfig"
        :mode="mode"
        v-model="valueHtml"
        style="height: 580px; overflow-y: hidden"
        @onCreated="handleCreated"
        @onChange="handleChange"
        @onDestroyed="handleDestroyed"
        @onFocus="handleFocus"
        @onBlur="handleBlur"
        @customAlert="customAlert"
        @customPaste="customPaste"
      />
    </div>
    <!-- <div style="margin-top: 10px">
      <textarea
        v-model="valueHtml"
        readonly
        style="width: 100%; height: 200px; outline: none"
      ></textarea>
    </div> -->
  </div>
</template>

<script lang="ts" setup>
import '@wangeditor/editor/dist/css/style.css'
import { onBeforeUnmount, ref, shallowRef, toRefs, onMounted } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { DomEditor } from '@wangeditor/editor'

// 初始化 MENU_CONF 属性
const editorConfig: Partial<any> = {
  // TS 语法
  placeholder: '请输入内容...',
  MENU_CONF: {}
}

//代码高亮
editorConfig.MENU_CONF['codeSelectLang'] = {
  // 代码语言
  codeLangs: [
    { text: 'CSS', value: 'css' },
    { text: 'HTML', value: 'html' },
    { text: 'XML', value: 'xml' }
  ]
}

//上传图片配置---服务端地址-必填，否则上传图片会报错
editorConfig.MENU_CONF['uploadImage'] = {
  server: '/api/upload',
  // form-data fieldName ，默认值 'wangeditor-uploaded-image'
  fieldName: 'your-custom-name',
  // 单个文件的最大体积限制，默认为 2M
  maxFileSize: 1 * 1024 * 1024, // 1M
  // 最多可上传几个文件，默认为 100
  maxNumberOfFiles: 10,
  // 选择文件时的类型限制，默认为 ['image/*'] 。如不想限制，则设置为 []
  allowedFileTypes: ['image/*'],
  // 自定义上传参数，例如传递验证的 token 等。参数会被添加到 formData 中，一起上传到服务端。
  meta: {
    token: 'xxx',
    otherKey: 'yyy'
  },
  // 将 meta 拼接到 url 参数中，默认 false
  metaWithUrl: false,
  // 自定义增加 http  header
  headers: {
    Accept: 'text/x-json',
    otherKey: 'xxx'
  },
  // 跨域是否传递 cookie ，默认为 false
  withCredentials: true,
  // 超时时间，默认为 10 秒
  timeout: 5 * 1000, // 5 秒
  // 上传之前触发
  onBeforeUpload(file: File) {
    // TS 语法
    // onBeforeUpload(file) {    // JS 语法
    // file 选中的文件，格式如 { key: file }
    console.log('file', file)
    return file

    // 可以 return
    // 1. return file 或者 new 一个 file ，接下来将上传
    // 2. return false ，不上传这个 file
  },
  // 上传进度的回调函数
  onProgress(progress: number) {
    // TS 语法
    // onProgress(progress) {       // JS 语法
    // progress 是 0-100 的数字
    console.log('progress', progress)
  },

  // 单个文件上传成功之后
  onSuccess(file: File, res: any) {
    /*
    【特别注意】服务端 response body 格式要求如下：
    上传成功的返回格式： 
    {
    "errno": 0, // 注意：值是数字，不能是字符串
    "data": {
        "url": "xxx", // 图片 src ，必须
        "alt": "yyy", // 图片描述文字，非必须
        "href": "zzz" // 图片的链接，非必须
    }
   }
  */
    // TS 语法
    // onSuccess(file, res) {          // JS 语法
    console.log(`${file.name} 上传成功`, res)
  },

  // 单个文件上传失败
  onFailed(file: File, res: any) {
    // TS 语法
    // onFailed(file, res) {           // JS 语法
    console.log(`${file.name} 上传失败`, res)
  },

  // 上传错误，或者触发 timeout 超时
  onError(file: File, err: any, res: any) {
    // TS 语法
    // onError(file, err, res) {               // JS 语法
    console.log(`${file.name} 上传出错`, err, res)
  }
}

const Props = defineProps({
  height: {
    type: String,
    defalut: '600px'
  }
})
const { height } = toRefs(Props)
// 编辑器实例，必须用 shallowRef，重要！
const editorRef = shallowRef()

// 内容 HTML
const valueHtml = ref('')
const mode = ref('default') // // 或 'simple'
let editor = null
let toolbar = null
// 模拟 ajax 异步获取内容
onMounted(() => {
  // setTimeout(() => {
  //   valueHtml.value = '<p>请输入内容...</p>'
  // }, 1500)
  setTimeout(() => {
    toolbarConfig.insertKeys = {
      index: 32, // 插入的位置，基于当前的 toolbarKeys
      keys: 'fullScreens'
    }
    editor = editorRef.value
    toolbar = DomEditor.getToolbar(editor)
    const curToolbarConfig = toolbar.getConfig()
    // console.log(curToolbarConfig.toolbarKeys) // 当前菜单排序和分组
  }, 100)
})
const toolbarConfig = {}

const emits = defineEmits(['resultHtml'])
// 组件销毁时，也及时销毁编辑器，重要！
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return

  editor.destroy()
})

// 编辑器回调函数
const handleCreated = (editor: any) => {
  editorRef.value = editor // 记录 editor 实例，重要！
}
//获取html数据
const handleChange = (editor: { getHtml: () => any }) => {
  console.log('change:', editor.getHtml())
  const imgRegEx = /<img.*?>/gi
  const richText = valueHtml.value
  valueHtml.value = richText.replace(imgRegEx, (match) => {
    console.log(match)
    return match.replace(/<img/, '<img style="width:100%;"')
  })
  emits('resultHtml', editor.getHtml())
  console.log('change:', editor.getHtml())
}
const handleDestroyed = (editor: any) => {
  console.log('destroyed', editor)
}
//获取焦点处理
const handleFocus = (editor: any) => {
  //console.log('focus', editor)
  if (editor) return
}
//失出焦点处理
const handleBlur = (editor: any) => {
  //console.log('blur', editor)
  if (editor) return
}
const customAlert = (info: any, type: any) => {
  alert(`【自定义提示】${type} - ${info}`)
}
const customPaste = (
  editor: { insertText: (arg0: string) => void },
  event: any,
  callback: (arg0: boolean) => void
) => {
  console.log('ClipboardEvent 粘贴事件对象', event)
  // 自定义插入内容
  editor.insertText('xxx')
  // 返回值（注意，vue 事件的返回值，不能用 return）
  callback(false) // 返回 false ，阻止默认粘贴行为
  // callback(true) // 返回 true ，继续默认的粘贴行为
}

//获取文本
const insertText = () => {
  const editor = editorRef.value
  if (editor == null) return
  editor.insertText('hello world')
}

//打印html
const printHtml = () => {
  const editor = editorRef.value
  if (editor == null) return
  console.log(editor.getHtml())
}
//编辑器不可编辑
const disable = () => {
  const editor = editorRef.value
  if (editor == null) return
  editor.disable()
}

defineExpose({
  insertText,
  printHtml,
  disable
})
</script>
